using Abp.Notifications;
using Abp.Zero.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Mt.Organizations;
using Mt.Site.Core.AccessStatistics.Entities;
using Mt.Site.Core.Authorization.Delegation;
using Mt.Site.Core.Authorization.Users.Entities;
using Mt.Site.Core.BackGroundJobs.Entities;
using Mt.Site.Core.Base.Authorization.Roles;
using Mt.Site.Core.Base.Authorization.Users;
using Mt.Site.Core.Base.Domain.Entities.ShortId;
using Mt.Site.Core.Base.Localization;
using Mt.Site.Core.Cache.Entities;
using Mt.Site.Core.Chat;
using Mt.Site.Core.ContentManagement.Entities;
using Mt.Site.Core.CustomConfigurations;
using Mt.Site.Core.DataLogs;
using Mt.Site.Core.DiyContent.Form.Entities;
using Mt.Site.Core.Friendships;
using Mt.Site.Core.Members;
using Mt.Site.Core.Messages_;
using Mt.Site.Core.MultiTenancy;
using Mt.Site.Core.Navigations.Entities;
using Mt.Site.Core.Notifications;
using Mt.Site.Core.Organizations.Posts;
using Mt.Site.Core.SEO;
using Mt.Site.Core.StaticPages;
using Mt.Site.Core.Storage;
using Mt.Site.Core.Storage.File_;
using Mt.Site.Core.Taxonomys.Entities;
using Mt.Site.Core.VerifyCodes;
using Mt.Site.Core.VersionBackup.Entities;
using Mt.Site.Core.WorkFlows.Design.Entities;
using Mt.Site.Core.WorkFlows.Process.Entities;

namespace Mt.Site.EntityFrameworkCore
{
    public static class MtSiteDbModelBuilderExtensions
    {

        #region 批量改表名

        /// <summary>
        /// 系统相关的表及公用信息表的前缀
        /// Can be null/empty string to clear the prefix.
        /// </summary>
        /// <param name="modelBuilder">Model builder.</param>
        /// <param name="prefix">Table prefix, or null to clear prefix.</param>
        /// <param name="schemaName">The database schema of the table.</param>
        public static void ChangeSysTablePrefix(this ModelBuilder modelBuilder, string prefix, string schemaName = null)
        {
            prefix = prefix ?? "";
            ChangeBaseSysTablePrefix(modelBuilder, prefix, schemaName);
        }

        /// <summary>
        /// 前台展示内容相关表批量改名
        /// </summary>
        /// <param name="modelBuilder"></param>
        /// <param name="prefix"></param>
        /// <param name="schemaName"></param>
        public static void ChangeContentTablePrefix(this ModelBuilder modelBuilder, string prefix, string schemaName = null)
        {
            prefix = prefix ?? "";

            ChangeBaseContentTablePrefix(modelBuilder,prefix, schemaName);

            modelBuilder.SetTableName<Messages>(prefix + "Messages", schemaName);
            modelBuilder.SetTableName<Member>(prefix + "Member", schemaName);
            modelBuilder.SetTableName<MemberInfo>(prefix + "MemberInfo", schemaName);
            modelBuilder.SetTableName<VerifyCode>(prefix + "VerifyCode", schemaName);
            modelBuilder.SetTableName<ContentBase>(prefix + "Content", schemaName);
            modelBuilder.SetTableName<Content>(prefix + "Content", schemaName);
            modelBuilder.SetTableName<Content2>(prefix + "Content", schemaName);
            modelBuilder.SetTableName<ContentBody>(prefix + "ContentBody", schemaName);
            modelBuilder.SetTableName<ContentField>(prefix + "ContentField", schemaName);
            modelBuilder.SetTableName<DataLog>(prefix + "DataLog", schemaName);
            modelBuilder.SetTableName<Taxonomy>(prefix + "Taxonomys", schemaName);
            modelBuilder.SetTableName<TaxonomysItem>(prefix + "TaxonomysItem", schemaName);
            modelBuilder.SetTableName<TaxonomysItemBind>(prefix + "TaxonomysItemBind", schemaName);
            modelBuilder.SetTableName<IPInfo>(prefix + "IPInfos", schemaName);
            modelBuilder.SetTableName<AccessGeneral>(prefix + "AccessGeneral", schemaName);
            modelBuilder.SetTableName<AccessData>(prefix + "AccessData", schemaName);

            modelBuilder.SetTableName<VersionInfo>(prefix + "VersionInfo", schemaName);
            modelBuilder.SetTableName<BackupBody>(prefix + "BackupBody", schemaName);
            modelBuilder.SetTableName<BackupField>(prefix + "BackupField", schemaName);

            modelBuilder.SetTableName<WorkFlow>(prefix + "WorkFlow", schemaName);
            modelBuilder.SetTableName<WorkFlowCategeory>(prefix + "WorkFlowCategeory", schemaName);
            modelBuilder.SetTableName<WorkFlowForm>(prefix + "WorkFlowForm", schemaName);
            modelBuilder.SetTableName<WorkFlowLogs>(prefix + "WorkFlowLogs", schemaName);
            modelBuilder.SetTableName<WorkFlowNode>(prefix + "WorkFlowNode", schemaName);
            modelBuilder.SetTableName<WorkFlowPaper>(prefix + "WorkFlowPaper", schemaName);
            modelBuilder.SetTableName<WorkFlowPaperArchive>(prefix + "WorkFlowPaperArchive", schemaName);
            modelBuilder.SetTableName<WorkFlowPaperData>(prefix + "WorkFlowPaperData", schemaName);
            modelBuilder.SetTableName<WorkFlowPaperListCtrl>(prefix + "WorkFlowPaperListCtrl", schemaName);
            modelBuilder.SetTableName<WorkFlowPaperListCtrlData>(prefix + "WorkFlowPaperListCtrlData", schemaName);
            modelBuilder.SetTableName<WorkFlowProcess>(prefix + "WorkFlowProcess", schemaName);
            modelBuilder.SetTableName<PeriodicBackgroundJobLog>(prefix + "PeriodicBackgroundJobLogs", schemaName);
            modelBuilder.SetTableName<WorkFlowRelationship>(prefix + "WorkFlowRelationship", schemaName);
            modelBuilder.SetTableName<WorkFlowProcessMsg>(prefix + "WorkFlowProcessMsg", schemaName);
            modelBuilder.SetTableName<WorkFlowRunTime>(prefix + "WorkFlowRunTime", schemaName);
            modelBuilder.SetTableName<CommonShortMsg>(prefix + "CommonShortMsg", schemaName);
        }

        #region base

        /// <summary>
        /// 系统相关的表及公用信息表的前缀
        /// Can be null/empty string to clear the prefix.
        /// </summary>
        /// <param name="modelBuilder">Model builder.</param>
        /// <param name="prefix">Table prefix, or null to clear prefix.</param>
        /// <param name="schemaName">The database schema of the table.</param>
        public static void ChangeBaseSysTablePrefix(ModelBuilder modelBuilder, string prefix, string schemaName = null)
        {
            prefix = prefix ?? "";

            //Abp.ZeroCore，Abp 中的表
            modelBuilder.ChangeAbpTablePrefix<Tenant, Role, User>(prefix, schemaName);

            modelBuilder.SetTableName<RolePermission>(prefix + "Permissions", schemaName);
            modelBuilder.SetTableName<UserPermission>(prefix + "Permissions", schemaName);
            modelBuilder.SetTableName<MtApplicationLanguage>(prefix + "Languages", schemaName);
            modelBuilder.SetTableName<MtOrganizationUnit>(prefix + "OrganizationUnits", schemaName);
            modelBuilder.SetTableName<ShortIdTb>(prefix + "ShortIds", schemaName);

            modelBuilder.SetTableName<CustomConfiguration>(prefix + "CustomConfigurations", schemaName);
            modelBuilder.SetTableName<ChatMessage>(prefix + "ChatMessages", schemaName);
            modelBuilder.SetTableName<Friendship>(prefix + "Friendships", schemaName);
            modelBuilder.SetTableName<Seo>(prefix + "Seos", schemaName);
            modelBuilder.SetTableName<StaticPage>(prefix + "StaticPages", schemaName);
            modelBuilder.SetTableName<UserDelegation>(prefix + "UserDelegations", schemaName);
            modelBuilder.SetTableName<UserExtension>(prefix + "UserExtension", schemaName);
            modelBuilder.SetTableName<MtUserNotificationInfo>(prefix + "UserNotifications", schemaName);

            modelBuilder.SetTableName<CacheBackUp>(prefix + "CacheBackUp", schemaName);
        }

        /// <summary>
        /// 前台展示内容相关表批量改名
        /// </summary>
        /// <param name="modelBuilder"></param>
        /// <param name="prefix"></param>
        /// <param name="schemaName"></param>
        public static void ChangeBaseContentTablePrefix(ModelBuilder modelBuilder, string prefix, string schemaName = null)
        {
            prefix = prefix ?? "";

            modelBuilder.SetTableName<Menu>(prefix + "Menus", schemaName);
            modelBuilder.SetTableName<ContentMenu>(prefix + "ContentMenus", schemaName);
            modelBuilder.SetTableName<BackEndModule>(prefix + "BackEndModules", schemaName);
            modelBuilder.SetTableName<FrontEndPage>(prefix + "FrontEndPages", schemaName);
            modelBuilder.SetTableName<PageView>(prefix + "PageViews", schemaName);
            modelBuilder.SetTableName<RouteSetting>(prefix + "RouteSettings", schemaName);
            modelBuilder.SetTableName<Bundling>(prefix + "Bundlings", schemaName);
            modelBuilder.SetTableName<MenuConfig>(prefix + "MenuConfigs", schemaName);

            modelBuilder.SetTableName<ContentStorage>(prefix + "ContentStorages", schemaName);
            modelBuilder.SetTableName<FileObject>(prefix + "FileObjects", schemaName);
            modelBuilder.SetTableName<BinaryObject>(prefix + "BinaryObjects", schemaName);
            modelBuilder.SetTableName<ChannelObject>(prefix + "ChannelObjects", schemaName);

            modelBuilder.SetTableName<Directories>(prefix + "Directories", schemaName);
            modelBuilder.SetTableName<FileLibrary>(prefix + "FileLibrary", schemaName);
            modelBuilder.SetTableName<TemporaryFile>(prefix + "TemporaryFile", schemaName);
            modelBuilder.SetTableName<FileObjectEx>(prefix + "FileObjectEx", schemaName);

            modelBuilder.SetTableName<Post>(prefix + "Post", schemaName);
            modelBuilder.SetTableName<PostOrganization>(prefix + "PostOrganization", schemaName);
            modelBuilder.SetTableName<UserPost>(prefix + "UserPost", schemaName);
        }

        #endregion

        #endregion

        /// <summary>
        /// 添加索引
        /// </summary>
        /// <param name="modelBuilder"></param>
        public static void AddIndexForMtSiteDbContext(this ModelBuilder modelBuilder)
        {
            AddIndexForMtSiteBaseDbContext(modelBuilder);

            modelBuilder.Entity<Messages>(b =>
            {
                b.HasIndex(e => new { e.TenantId, e.Language, e.AuxiliaryId });
            });
            modelBuilder.Entity<Messages>(b =>
            {
                b.HasIndex(e => new { e.TenantId, e.Language, e.MenuId });
            });

            modelBuilder.Entity<VerifyCode>(b =>
            {
                b.HasIndex(e => new { e.TenantId, e.AuxiliaryId });
            });

            modelBuilder.Entity<MemberInfo>(b =>
            {
                b.HasIndex(e => new { e.TenantId, e.Language, e.MemberID });
            });


            modelBuilder.Entity<ContentBase>(b =>
            {
                b.HasIndex(e => new { e.TenantId, e.Language, e.AuxiliaryId });                    //前台内容详情

                b.HasIndex(e => new { e.TenantId, e.Language, e.MenuId, e.RelateId, e.Key, e.IsActive });       // 1对1 的 列表页 后台

                b.HasIndex(e => new { e.TenantId, e.Language, e.MenuId, e.RelateId, e.IsActive, e.Order });       // 1对1 的 列表页 前台

                b.HasIndex(e => new { e.TenantId, e.Language, e.IsActive });       // 1对多 的 列表页
            });

            modelBuilder.Entity<ContentBody>(b =>
            {
                b.HasIndex(e => new { e.ContentId });
            });
            modelBuilder.Entity<ContentField>(b =>
            {
                b.HasIndex(e => new { e.ContentId });
            });
            modelBuilder.Entity<AccessData>(b =>
            {
                b.HasIndex(e => new { e.Acount });
            });

            modelBuilder.Entity<TaxonomysItem>(b =>
            {
                b.HasIndex(e => new { e.Code });
            });
            modelBuilder.Entity<TaxonomysItemBind>(b =>
            {
                b.HasIndex(e => new { e.TenantId });
            });

            modelBuilder.Entity<BackupBody>(b =>
            {
                b.HasIndex(e => new { e.ContentId });
            });
            modelBuilder.Entity<BackupField>(b =>
            {
                b.HasIndex(e => new { e.ContentId });
            });
            modelBuilder.Entity<VersionInfo>(b =>
            {
                b.HasIndex(e => new { e.ContentId });
            });

            #region 工作流

            modelBuilder.Entity<WorkFlowNode>(b =>
            {
                b.HasIndex(e => new { e.TenantId, e.WorkflowId });
            });
            modelBuilder.Entity<WorkFlowForm>(b =>
            {
                b.HasIndex(e => new { e.TenantId, e.WorkFlowId });
            });

            modelBuilder.Entity<WorkFlowLogs>(b =>
            {
                b.HasIndex(e => new { e.PaperId });
            });

            modelBuilder.Entity<WorkFlowPaper>(b =>
            {
                b.HasIndex(e => new { e.PaperState, e.WorkFlowId, e.CreationTime });
                b.HasIndex(e => new { e.ReferNumber });
            });
            modelBuilder.Entity<WorkFlowPaperArchive>(b =>
            {
                b.HasIndex(e => new { e.CreationTime });                         //归档管理
                b.HasIndex(e => new { e.WorkFlowId, e.CreationTime });           //归档管理
                //b.HasIndex(e => new { e.WorkFlowId, e.RegistrationTime });       //收文统计
                //b.HasIndex(e => new { e.ReferNumber });
                //b.HasIndex(e => new { e.WenHaoId, e.WhYear, e.WhNumber });
                //b.HasIndex(e => new { e.Signer });       //线索抓取（Signer 存放了来源id）
            });

            modelBuilder.Entity<WorkFlowProcess>(b =>
            {
                b.HasIndex(e => new { e.PaperId });
                b.HasIndex(e => new { e.State, e.UserId, e.StartTime });
            });

            modelBuilder.Entity<WorkFlowPaperData>(b =>
            {
                b.HasIndex(e => new { e.PaperId });
            });
            modelBuilder.Entity<WorkFlowPaperListCtrlData>(b =>
            {
                b.HasIndex(e => new { e.RelateId });
            });

            modelBuilder.Entity<WorkFlowRelationship>(b =>
            {
                b.HasIndex(e => new { e.PaperId });
            });
            modelBuilder.Entity<WorkFlowProcessMsg>(b =>
            {
                b.HasIndex(e => new { e.PaperId });
            });
            modelBuilder.Entity<WorkFlowRunTime>(b =>
            {
                b.HasIndex(e => new { e.UserId, e.State, e.StartTime, e.PaperId });
                b.HasIndex(e => new { e.PaperId });
            });

            modelBuilder.Entity<CommonShortMsg>(b =>
            {
                b.HasIndex(e => new { e.CreatorUserId });
            });
            
            #endregion

            modelBuilder.Entity<PeriodicBackgroundJobLog>(b =>
            {
                b.HasIndex(e => new { e.Date });
            });

            modelBuilder.Entity<TenantNotificationInfo>(b =>
            {
                b.HasIndex(e => new { e.TenantId, e.NotificationName, e.EntityId });
            });
        }
        public static void AddIndexForMtSiteBaseDbContext(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<CacheBackUp>(b =>
            {
                b.HasIndex(e => new { e.DataType });
                b.HasIndex(e => new { e.DataId });
            });

            modelBuilder.Entity<ShortIdTb>(b =>
            {
                b.HasIndex(e => new { e.AuxiliaryId });
            });

            modelBuilder.Entity<BinaryObject>(b =>
            {
                b.HasIndex(e => new { e.TenantId });
            });

            modelBuilder.Entity<ChatMessage>(b =>
            {
                b.HasIndex(e => new { e.TenantId, e.UserId, e.ReadState });
                b.HasIndex(e => new { e.TenantId, e.TargetUserId, e.ReadState });
                b.HasIndex(e => new { e.TargetTenantId, e.TargetUserId, e.ReadState });
                b.HasIndex(e => new { e.TargetTenantId, e.UserId, e.ReadState });
            });

            modelBuilder.Entity<Friendship>(b =>
            {
                b.HasIndex(e => new { e.TenantId, e.UserId });
                b.HasIndex(e => new { e.TenantId, e.FriendUserId });
                b.HasIndex(e => new { e.FriendTenantId, e.UserId });
                b.HasIndex(e => new { e.FriendTenantId, e.FriendUserId });
            });

            #region 附件

            modelBuilder.Entity<FileObject>(b =>
            {
                b.HasIndex(e => new { e.TenantId, e.Language, e.ContentId });
                b.HasIndex(e => new { e.Sha1 });
                b.HasIndex(e => new { e.FileUrl });
                b.HasIndex(e => new { e.IsTemporary }); 
            });

            modelBuilder.Entity<ContentStorage>(b =>
            {
                b.HasIndex(e => new { e.TenantId, e.ContentId });
            });

            #endregion

            #region 栏目
            modelBuilder.Entity<Menu>(b =>
            {
                b.HasIndex(e => new { e.TenantId, e.Code });
                b.HasIndex(e => new { e.TenantId, e.AuxiliaryId });

                b.HasMany(e => e.ChannelObjects)
                  .WithOne()
                  .HasForeignKey(e => e.MenuId);

                b.HasMany(e => e.Bundlings)
                  .WithOne()
                  .HasForeignKey(e => e.MenuId);
            });

            modelBuilder.Entity<ContentMenu>(b =>
            {
                b.HasIndex(e => new { e.MenuId, e.RelateId, e.Order, e.ContentId });
                b.HasIndex(e => new { e.MenuId, e.RelateId, e.PublishTime, e.ContentId });
                b.HasIndex(e => new { e.ContentId });
            });

            #endregion

            modelBuilder.Entity<UserExtension>(b =>
            {
                b.HasIndex(e => new { e.UserId });
            });

            modelBuilder.Entity<FrontEndPage>(b =>
            {
                b.HasIndex(e => e.BackEndModuleId);
                b.HasMany(p => p.PageViews)
                    .WithOne()
                    .HasForeignKey(p => p.FrontEndPageId);
            });

            modelBuilder.Entity<RouteSetting>(b =>
            {
                b.HasIndex(e => new { e.TenantId, e.RelatedId });
            });

            modelBuilder.Entity<MenuConfig>(b =>
            {
                b.HasIndex(e => new { e.TenantId, e.MenuId });
            });

            modelBuilder.Entity<Seo>(b =>
            {
                b.HasIndex(e => new { e.TenantId, e.RelatedId });
            });

            modelBuilder.Entity<StaticPage>(b =>
            {
                b.HasIndex(e => e.RealUrl);
            });
            modelBuilder.Entity<UserDelegation>(b =>
            {
                b.HasIndex(e => new { e.TenantId, e.SourceUserId });
                b.HasIndex(e => new { e.TenantId, e.TargetUserId });
            });

            modelBuilder.Entity<Post>(b =>
            {
                b.HasIndex(e => new { e.TenantId, e.OrganizationId });
            });
            modelBuilder.Entity<PostOrganization>(b =>
            {
                b.HasIndex(e => new { e.TenantId, e.OrganizationId });
                b.HasIndex(e => new { e.TenantId, e.PostId });
            });
            modelBuilder.Entity<UserPost>(b =>
            {
                b.HasIndex(e => new { e.TenantId, e.PostId });
                b.HasIndex(e => new { e.TenantId, e.UserId });
            });

            modelBuilder.Entity<TemporaryFile>(b =>
            {
                b.HasIndex(e => new { e.FileUrl });
            });

            modelBuilder.Entity<Directories>(b =>
            {
                b.HasIndex(e => new { e.TenantId, e.ParentId, e.Owners });
            });

            modelBuilder.Entity<FileLibrary>(b =>
            {
                b.HasIndex(e => new { e.Sha1 });
                b.HasIndex(e => new { e.FileUrl });
                b.HasIndex(e => new { e.DirectoryId, e.CreationTime });
            });
            modelBuilder.Entity<FileObjectEx>(b =>
            {
                b.HasIndex(e => new { e.OriginFileUrl });
            });
        }

        public static void SetTableName<TEntity>(this ModelBuilder modelBuilder, string tableName, string schemaName)
            where TEntity : class
        {
            if (schemaName == null)
            {
                modelBuilder.Entity<TEntity>().ToTable(tableName);
            }
            else
            {
                modelBuilder.Entity<TEntity>().ToTable(tableName, schemaName);
            }
        }
    }
}
